//
// Created by Administrator on 2021/5/3.
//

/*
编写一个程序，找到两个单链表相交的起始节点。

注意：

如果两个链表没有交点，返回 null.
在返回结果后，两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度，且仅用 O(1) 内存。

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/intersection-of-two-linked-lists
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。*/
#include <iostream>
#include <unordered_set>

// Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;

    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // 暴力 记录所有节点  查看是否交叉
        std::unordered_set<ListNode *> seen;
        while (headA) {
            seen.insert(headA);
            headA = headA->next;
        }
        while (headB) {
            if (seen.find(headB) != seen.end()) return headB;
            headB = headB->next;
        }
        return nullptr;
    }

    ListNode *getIntersectionNode2(ListNode *headA, ListNode *headB) {
        /**
         双指针
         创建两个指针 pA 和 pB，分别初始化为链表 A 和 B 的头结点。然后让它们向后逐结点遍历。
        当 pA 到达链表的尾部时，将它重定位到链表 B 的头结点 (你没看错，就是链表 B);
         类似的，当 pB 到达链表的尾部时，将它重定位到链表 A 的头结点。
        若在某一时刻 pA 和 pB 相遇，则 pA/pB 为相交结点。
        想弄清楚为什么这样可行, 可以考虑以下两个链表: A={1,3,5,7,9,11} 和 B={2,4,9,11}，
         相交于结点 9。 由于 B.length (=4) < A.length (=6)，pB比 pA 少经过 2 个结点，会先到达尾部。
         将 pB 重定向到 A 的头结点，pA 重定向到 B 的头结点后，pB 要比 pA 多走 2 个结点。因此，它们会同时到达交点。
        如果两个链表存在相交，它们末尾的结点必然相同。因此当 pA/pB 到达链表结尾时，
         记录下链表 A/B 对应的元素。若最后元素不相同，则两个链表不相交。
         */
        if (headA == nullptr or headB == nullptr) return nullptr;
        // 不破坏链表
        ListNode *head1 = headA;
        ListNode *head2 = headB;
        while (head1 != head2) {
            // 如果不相交，将同时到达最后对方一个元素，且同时指向空指针
            head1 = head1 != nullptr ? head1->next : headB;
            head2 = head2 != nullptr ? head2->next : headA;
        }
        return head1;
    }
};

int main() {
    ListNode a1{4}, a2{1}, b1{5}, b2{0}, b3{1}, c1{8}, c2{4}, c3{5};
    a1.next = &a2;
    a2.next = &c1;
    b1.next = &b2;
    b2.next = &b3;
    b3.next = &c1;
    c1.next = &c2;
    c2.next = &c3;
    Solution sol;
    auto ans = sol.getIntersectionNode2(&a1, &b1);
    std::cout << (ans != nullptr ? ans->val : -1) << std::endl;
    return 0;
}